/////////////////////////////////////////////////////////////////////////////
// Name:        commandeditor.h
// Purpose:     Command editor classes
// Author:      Julian Smart
// Modified by:
// Created:     2008-11-18
// RCS-ID:      $Id$
// Copyright:   (c) Julian Smart
// Licence:     New BSD License
/////////////////////////////////////////////////////////////////////////////

#ifndef __COMMANDEDITOR_H__
#define __COMMANDEDITOR_H__

#include "wx/dynarray.h"

class wxEditorCommandInfo;
class wxOutputStream;
class wxDataOutputStream;
class wxInputStream;
class wxDataInputStream;

enum wxEditorCommandType
{
    wxEditorCommandDefault,  // system default editor or viewer
    wxEditorCommandInternal, // internal editor or viewer
    wxEditorCommandExternal  // custom external editor or viewer
};

enum wxEditorMediaType
{
    wxEditorCommandMediaTypeUnknown,
    wxEditorCommandMediaTypeEbook,
    wxEditorCommandMediaTypeAudio,
    wxEditorCommandMediaTypeVideo,
    wxEditorCommandMediaTypeImage,
    wxEditorCommandMediaTypeDocument
};

/*!
 * Information about a single command (for editing or viewing)
 */

#define wxEDITOR_COMMAND_DEFAULT_NAME   wxTRANSLATE("Default")
#define wxEDITOR_COMMAND_INTERNAL_NAME  wxTRANSLATE("Internal")

class wxEditorCommand: public wxObject
{
public:
    wxEditorCommand() { Init(); }
    wxEditorCommand(const wxEditorCommand& info) { Copy(info); }

    void Init();
    void Copy(const wxEditorCommand& info);
    void operator=(const wxEditorCommand& info) { Copy(info); }

    bool IsDefault() const { return m_commandType == wxEditorCommandDefault; }
    bool IsInternal() const { return m_commandType == wxEditorCommandInternal; }
    bool IsExternal() const { return m_commandType == wxEditorCommandExternal; }

    /// Compatibility
    void SetDefault(bool isDefault = true) { m_commandType = (isDefault ? wxEditorCommandDefault : wxEditorCommandExternal); }
    void SetInternal(bool isInternal = true) { m_commandType = (isInternal ? wxEditorCommandInternal : wxEditorCommandExternal); }

    wxEditorCommandType GetCommandType() const { return m_commandType; }
    void SetCommandType(wxEditorCommandType t) { m_commandType = t; }

    bool Save(wxOutputStream& stream, wxDataOutputStream& dataStream);
    bool Load(wxInputStream& stream, wxDataInputStream& dataStream);

    void Enable(bool enable) { m_enabled = enable; }

    wxString            m_title;
    wxString            m_command;
    bool                m_enabled;
    wxEditorCommandType m_commandType;
    // bool            m_isDefault; // system command
};

WX_DECLARE_OBJARRAY(wxEditorCommand, wxEditorCommandArray);

/*!
 * Represents a particular file type, and contains editors and viewers
 */

class wxEditorCommands: public wxObject
{
public:
    wxEditorCommands(const wxString& fileTypeName, const wxString& fileTypeDescription, const wxString& fileTypeExtensions, int mediaType = wxEditorCommandMediaTypeUnknown)
    { Init(); m_fileTypeName = fileTypeName; m_fileTypeDescription = fileTypeDescription; m_fileTypeExtensions = fileTypeExtensions; m_mediaType = mediaType; }

    wxEditorCommands() { Init(); }
    
    wxEditorCommands(const wxEditorCommands& commands) { Copy(commands); }

    void Init();
    void Copy(const wxEditorCommands& commands);
    void operator=(const wxEditorCommands& commands) { Copy(commands); }

    const wxString& GetFileTypeName() const { return m_fileTypeName; }
    const wxString& GetFileTypeDescription() const { return m_fileTypeDescription; }
    const wxString& GetFileTypeExtensions() const { return m_fileTypeExtensions; }
    const wxString& GetDefaultViewerName() const { return m_defaultViewerName; }
    const wxString& GetDefaultEditorName() const { return m_defaultEditorName; }

    // Extension to use when getting the default command for editing
    const wxString& GetFileTypeExtensionForDefaultViewing() const { return m_fileTypeExtensionForDefaultViewing; }

    // Extension to use when getting the default command for viewing
    const wxString& GetFileTypeExtensionForDefaultEditing() const { return m_fileTypeExtensionForDefaultEditing; }
    
    const wxEditorCommandArray& GetViewers() const { return m_viewers; }
    wxEditorCommandArray& GetViewers() { return m_viewers; }

    const wxEditorCommandArray& GetEditors() const { return m_editors; }
    wxEditorCommandArray& GetEditors() { return m_editors; }

    wxArrayString GetViewerCommandNames(bool onlyEnabledCommands = true) const;
    wxArrayString GetEditorCommandNames(bool onlyEnabledCommands = true) const;

    /// Find viewer command
    wxEditorCommand* FindViewerCommand(const wxString& title) const;
    wxEditorCommand* FindViewerCommand(int i) const;
    wxEditorCommand* GetDefaultViewerCommand() const;

    /// Find editor command
    wxEditorCommand* FindEditorCommand(const wxString& title) const;
    wxEditorCommand* FindEditorCommand(int i) const;
    wxEditorCommand* GetDefaultEditorCommand() const;

    /// Get/set media type
    int GetMediaType() const { return m_mediaType; }
    void SetMediaType(int mediaType) { m_mediaType = mediaType; }

    bool Save(wxOutputStream& stream, wxDataOutputStream& dataStream);
    bool Load(wxInputStream& stream, wxDataInputStream& dataStream);

    /// Initialize default editors
    void InitializeDefaults(const wxString& extForDefaultViewing, const wxString& extForDefaultEditing, bool addInternal = true);

public:
    wxString                m_fileTypeName;
    wxString                m_fileTypeDescription;
    wxString                m_fileTypeExtensions;
    wxString                m_fileTypeExtensionForDefaultViewing;
    wxString                m_fileTypeExtensionForDefaultEditing;
    wxEditorCommandArray    m_viewers;
    wxEditorCommandArray    m_editors;

    // The name of the default viewer command (m_title)
    wxString                m_defaultViewerName;
    
    // The name of the default editor command (m_title)
    wxString                m_defaultEditorName;

    int                     m_mediaType;
};

WX_DECLARE_OBJARRAY(wxEditorCommands, wxEditorCommandsArray);

#define wxEDITOR_COMMAND_BY_TYPE        0x01
#define wxEDITOR_COMMAND_BY_EXTENSION   0x02

typedef enum {
    wxEDITOR_COMMAND_FAILURE,
    wxEDITOR_COMMAND_CANCELLED,
    wxEDITOR_COMMAND_SUCCESS
} wxEditorCommandGetCommandStatus;

/*!
 * Manages the database of commands
 */

class wxEditorCommandManager: public wxObject
{
public:
    wxEditorCommandManager() { Init(); }
    wxEditorCommandManager(const wxEditorCommandManager& manager) { Copy(manager); }
    ~wxEditorCommandManager();

    void Init();
    void Copy(const wxEditorCommandManager& manager);
    void operator=(const wxEditorCommandManager& manager) { Copy(manager); }

    /// Deletes the current popup menu, if there was one.
    void DeleteCommandMenu();

    /// Get current menu selection
    int GetSelection() const { return m_currentSelection; }

    /// Set current menu selection
    void SetSelection(int sel) { m_currentSelection = sel; }

    const wxEditorCommandsArray& GetFileTypes() const { return m_fileTypes; }
    wxEditorCommandsArray& GetFileTypes() { return m_fileTypes; }

    /// Finds the file type for the given name
    virtual wxEditorCommands* GetFileType(const wxString& name, int flags = wxEDITOR_COMMAND_BY_TYPE);

    /// Finds the current default viewer command for the given type
    virtual wxEditorCommand* GetDefaultViewer(const wxString& name, int flags = wxEDITOR_COMMAND_BY_TYPE);

    /// Finds the current default editor command for the given type
    virtual wxEditorCommand* GetDefaultEditor(const wxString& name, int flags = wxEDITOR_COMMAND_BY_TYPE);

    /// Launches viewer command for this file. If viewerCmdName is empty, uses the
    /// user-specified default command for this type.
    virtual bool LaunchViewer(const wxString& filename, const wxString& name, const wxString& viewerCmdName = wxEmptyString, int flags = wxEDITOR_COMMAND_BY_TYPE);

    /// Launches editor command for this file. If editorCmdName is empty, uses the
    /// user-specified default command for this type.
    virtual bool LaunchEditor(const wxString& filename, const wxString& name, const wxString& editorCmdName = wxEmptyString, int flags = wxEDITOR_COMMAND_BY_TYPE);

    /// Launches file
    virtual bool LaunchFile(const wxString& filename, const wxEditorCommand& cmd, const wxString& defaultExtForCmd = wxEmptyString);
    virtual bool LaunchFile(const wxEditorCommandInfo& info);

    /// Launch file either immediately or after user chooses from a menu.
    /// Add filenames and corresponding file types (e.g. "Epub files")
    virtual bool LaunchFile(wxWindow* win, const wxArrayString& filenames, const wxArrayString& fileTypes, bool editing, int flags = wxEDITOR_COMMAND_BY_TYPE);

    /// Single-file version of the above
    virtual bool LaunchFile(wxWindow* win, const wxString& filename, const wxString& fileType, bool editing, int flags = wxEDITOR_COMMAND_BY_TYPE);

    /// Get the command, possibly prompting via a menu
    virtual wxEditorCommandGetCommandStatus GetCommand(wxWindow* win, const wxArrayString& filenames, const wxArrayString& fileTypes, bool editing, wxEditorCommandInfo* info, int flags = wxEDITOR_COMMAND_BY_TYPE);

    /// Get the command, possibly prompting via a menu (single filename/type)
    virtual wxEditorCommandGetCommandStatus GetCommand(wxWindow* win, const wxString& filename, const wxString& fileType, bool editing, wxEditorCommandInfo* info, int flags = wxEDITOR_COMMAND_BY_TYPE);

    /// Call this from your own menu command handler to finish the LaunchFile sequence.
    virtual bool DoMenuCommand(wxCommandEvent& event);

    /// Set start and end menu ids
    void SetMenuIdRange(int start, int end) { m_startMenuId = start; m_endMenuId = end; }

    /// Adds a file type
    virtual void AddFileType(const wxEditorCommands& fileType);

    /// Deletes a file type
    virtual bool DeleteFileType(int i);

    /// Save
    virtual bool Save(wxOutputStream& stream, wxDataOutputStream& dataStream);
    virtual bool Save(const wxString& filename);

    /// Load
    virtual bool Load(wxInputStream& stream, wxDataInputStream& dataStream);
    virtual bool Load(const wxString& filename);

    /// Clear
    virtual void Clear();

    /// Override this to implement default file launching
    virtual bool DefaultLaunchFile(const wxString& filename) = 0;

    // Read an attribute name/value pair
    // Returns FALSE if the attribute name "END" was encountered
    static bool ReadAttributeValue(wxVariant& variant, wxDataInputStream& dataStream);
    
    // Writes an attribute name/value pair
    static bool WriteAttributeValue(const wxVariant& variant, wxDataOutputStream& dataStream);
    static bool WriteAttributeValue(const wxString& value, const wxString& name, wxDataOutputStream& dataStream);
    static bool WriteAttributeValue(long value, const wxString& name, wxDataOutputStream& dataStream);
    static bool WriteAttributeValue(int value, const wxString& name, wxDataOutputStream& dataStream);
    static bool WriteAttributeValue(double value, const wxString& name, wxDataOutputStream& dataStream);
    static bool WriteAttributeValue(bool value, const wxString& name, wxDataOutputStream& dataStream);
    
    // Write end of attributes marker
    static bool WriteAttributeEnd(wxDataOutputStream& dataStream);

public:
    wxEditorCommandsArray m_fileTypes;

    /// For launching command via a menu, if there are several alternatives
    bool            m_currentlyEditing;
    wxArrayString   m_currentFileTypes;
    wxArrayString   m_currentFilenames;
    wxArrayString   m_currentCmdChoices;
    wxMenu*         m_currentMenu;
    int             m_startMenuId;
    int             m_endMenuId;
    int             m_currentSelection;
};

/*!
 * Return info from GetCommand
 */

class wxEditorCommandInfo
{
public:
    wxEditorCommandInfo() { m_command = NULL; m_commands = NULL; m_editing = false; }

    wxEditorCommand*    m_command;
    wxEditorCommands*   m_commands;
    bool                m_editing;
    wxString            m_filename;
    wxString            m_commandName;
    wxString            m_fileType;
};


#endif
    // __COMMANDEDITOR_H__
